/*
  Copyright (c) 2008 Romain Gaucher <r@rgaucher.info>

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0
                
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/

#ifndef RANGE_H
#define RANGE_H

#include <string>
#include <sstream>
#include "intnumber.h"

std::string to_string(const IntNumber& m) {
	std::ostringstream os;
	os << m;
	return os.str();
}

template<unsigned int N, bool U>
class Range
{
	//! Our domain is defined by an upper bound and a lower bound
	IntNumber       lower,
	                upper;
	unsigned int   nbytes;
	bool             sign;
  public:
	// Ctor
	Range(const unsigned int& _nbytes = N, bool _unsigned = U) {
		sign   = not _unsigned;
		nbytes = _nbytes;
		if (_unsigned) {
			lower = 0;
			upper = 1; upper <<= nbytes; upper--; 
		}
		else {
			lower = 1; lower <<= (nbytes-1); lower = -lower;
			upper = 1; upper <<= (nbytes-1); upper--;
		}
	}
	
	Range(const Range& range) {
		lower = range.lower;
		upper = range.upper;
	}
	Range(const IntNumber& n) {
		lower = n;
		upper = n;
	}
	
	void operator=(const Range& range) {
		lower = range.min();
		upper = range.max();
	}
	
	// Dtor
	~Range() 
	{ /* */ }


	//! Return the upper bound
	inline IntNumber max() const { return upper; }
	//! Return the lower bound
	inline IntNumber min() const { return lower; }
	
	//! Set the lower bound
	inline IntNumber min(const IntNumber& _min) { 
		if (_min <= upper)
			lower = _min;
		else {
			// swap the order
			lower = upper;
			upper =  _min;
		}
		return lower;
	}

	//! Set the upper bound
	inline IntNumber max(const IntNumber& _max) { 
		if (_max >= lower)
			upper = _max;
		else {
			// swap the order
			upper = lower;
			lower =  _max;
		}
		return lower;
	}
	
	//! Is the value in the range?
	bool inRange(const IntNumber& value) const {
		if (value >= lower && upper >= value)
			return true;
		return false; 	
	}
	
	//! Print the state
	std::string string() const {
		std::string str;
		str += (std::string("[") + to_string(lower) + "," + to_string(upper) + "]");
		return str;		
	}
	
};

template<unsigned int N, bool U>
std::ostream& operator<<(std::ostream& os, const Range<N,U>& range) {
	os << range.string();
	return os;
}

#endif

